//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.denghq.projectbuilder.component.consul.config.configuration;

import com.denghq.projectbuilder.component.config.metadata.ConfigDescriptor;
import com.denghq.projectbuilder.component.config.spring.ConfigPropertySource;
import com.ecwid.consul.v1.ConsulClient;
import com.ecwid.consul.v1.kv.model.GetValue;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
import org.springframework.retry.annotation.Retryable;
import org.springframework.util.CollectionUtils;

import java.util.LinkedHashMap;
import java.util.List;

/**
 * 资源定位器，可用于定位外部资源，这里用来定位consul上key/value存储的数据
 */
@Order(0)
@Slf4j
public class ConsulConfigPropertySourceLocator implements PropertySourceLocator {

    private final ConsulConfigAutoRegister consulConfigAutoRegister;
    /**
     * 用于保存 key 和 key当前的index（index用于标记key当前的版本,通过CAS实现key的原子操作）
     */
    private final LinkedHashMap<String, Long> contextIndex = new LinkedHashMap();

    /**
     * 所有的配置类描述信息
     */
    @Getter
    private final List<ConfigDescriptor> configDescriptorList;

    public ConsulConfigPropertySourceLocator(ConsulClient consul, List<ConfigDescriptor> configDescriptorList, ConsulConfigAutoRegister consulConfigAutoRegister, ConsulConfigProperties properties) {
        this.configDescriptorList = configDescriptorList;
        this.consulConfigAutoRegister = consulConfigAutoRegister;
    }


    @Retryable(
            interceptor = "consulRetryInterceptor"
    )
    public PropertySource<?> locate(Environment environment) {
        if (!(environment instanceof ConfigurableEnvironment)) {
            return null;
        } else {
            CompositePropertySource composite = new CompositePropertySource("consul");
            List<GetValue> valueFromConsul = consulConfigAutoRegister.getValueFromConsul(configDescriptorList, contextIndex);
            if (!CollectionUtils.isEmpty(valueFromConsul)) {
                valueFromConsul.forEach(v -> {
                    ConfigPropertySource propertySource;
                    propertySource = this.create(v);
                    if (propertySource != null) {
                        composite.addPropertySource((propertySource));
                    }
                });
                log.warn(" 配置更新：{} ", composite.getPropertyNames());
            }
            return composite;
        }
    }

    private ConfigPropertySource create(GetValue value) {
        ConfigPropertySource propertySource = null;
        if (!CollectionUtils.isEmpty(configDescriptorList)) {
            for (int i = 0, len = configDescriptorList.size(); i < len; i++) {
                if (value.getKey().equals(configDescriptorList.get(i).getCategoryNo())) {
                    propertySource = new ConfigPropertySource(value.getKey(), value.getDecodedValue(), configDescriptorList.get(i));
                    propertySource.init();
                    break;
                }
            }
        }
        return propertySource;
    }

}
